package game.game;

import com.crunch.core.Actor;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * An actor implement game-specific functionality including instance initialization from a file.
 */
public abstract class GameActor extends Actor {
	public GameActor() {
		super();
	}

	public GameActor(int updatePriority) {
		super(updatePriority);
	}

	// override onGameActorCreate() instead
	@Override
	public final void onCreate() {
		destroyedForStateChange = false;
		getRoomState().addGameActor(this);
		onGameActorCreate();
	}

	// override onGameActorDestroy() instead
	@Override
	public final void onDestroy() {
		onGameActorDestroy();
		getRoomState().removeGameActor(this);
	}

	// override for custom creation code
	// this is called very first, before any init/load functions
	public void onGameActorCreate() {
	}

	// override for custom destruction code
	// onGameActorDestroy() should function properly even in the event that the object failed to initialize properly
	// e.g. onDestroy() should not crash if a physics entity was never initialized
	public void onGameActorDestroy() {
	}

	// used to initialize game state
	// this method should read from the JSONObject to initialize itself
	// in the case of failure, a JSONException should be thrown
	// if this occurs, onDestroy() will be called soon after
	public abstract void initState(JSONObject state)
			throws JSONException;

	// used to load game state
	public abstract void loadState(JSONObject state)
			throws JSONException;

	// used to save game state - return null if no state should be saved
	public abstract JSONObject saveState()
			throws JSONException;

	public RoomState getRoomState() {
		return (RoomState) getGameState();
	}

	// sends a message with the given data to the actor
	public void sendMessage(int id, Object data) {
		onReceiveMessage(id, data);
	}

	// override to process messages
	protected void onReceiveMessage(int id, Object data) {}

	// returns true if this game actor was destroyed for a state change, as opposed to an in-game event
	// a state change occurs when a room is initialized or loaded using deserialization
	// before this occurs, all existing game actors are first cleared
	// when objects are destroyed for a state change, they should not trigger any further in-game events
	// e.g. a projectile's onDestroy() method should not spawn particles during a state change, or destroy other actors
	public boolean wasDestroyedForStateChange() {
		return destroyedForStateChange;
	}

	// to be called by RoomState during state change
	void setDestroyedForStateChange() {
		destroyedForStateChange = true;
	}

	private boolean destroyedForStateChange;
}
